Skip to content

Clear stamped code-block height when Hide Info collapses a tool call - #5924

Merged
FadhlanR merged 2 commits into
mainfrom
cs-12097-plan
Sep 1, 2026
Merged

Clear stamped code-block height when Hide Info collapses a tool call#5924
FadhlanR merged 2 commits into
mainfrom
cs-12097-plan

Conversation

@FadhlanR

Copy link
Copy Markdown
Contributor

Problem

In an AI assistant room, expanding a completed tool call's code (ⓘ → "View Info") and then clicking "Hide Info" intermittently left a large empty area below the tool-call header. The Monaco editor was removed from the DOM but the container kept its expanded height.

Root cause

The scrollBottomIntoView modifier on the tool call's <CodeBlock> stamps an inline pixel height on the container sized to the editor's content:

element.style.height = `${editorHeight + heightOfOtherChildren}px`;

Nothing ever cleared it. The functional modifier consumed no tracked state that changes on toggle, so it only ran at install:

  • Normal mounts start collapsed, so at install there is no editor (getContentHeight() → 0, early return) — no height is stamped and collapse works.
  • The expanded/collapsed flag lives in the room resource (keyed by tool-request id) and survives component remounts. When a message re-mounts while its code area is open — reopening the AI assistant panel, re-entering the room, a submode switch, any list re-render — the modifier installs with the editor present and stamps the height. From then on "Hide Info" removes the editor but leaves the stamped height, so the empty block remains. This is why it was intermittent.

The inner editor div already self-sizes (the monaco-editor modifier sets and updates its height and CSS caps it), so the outer-container stamp is only for snug fit + scroll-into-view.

Fix

Make the modifier consume isDisplayingCode so it re-runs on toggle, and reset the inline height on the collapse / no-measurable-editor paths so the container returns to its header-only height.

Test

Adds an integration test that reproduces the remount-while-open condition (close + reopen the AI assistant panel with the code area expanded) and asserts that after "Hide Info" the editor is gone and the container has no leftover inline height.

Verification

  • Change is minimal and type-trivial (boolean guard + height reset + standard find test helper import).
  • This fresh worktree does not have host deps installed, so the browser test harness was not run locally — relying on CI to exercise the new test. Marking as draft accordingly.

The scrollBottomIntoView modifier on a tool call's code block stamped an
inline pixel height sized to the Monaco editor's content, but nothing ever
cleared it. When a tool-call message mounted while its code area was already
expanded (reopening the AI assistant panel, re-entering the room, a submode
switch), the modifier stamped the height at install; a later "Hide Info"
removed the editor but left the container at its expanded size, leaving an
empty gap below the header.

Make the modifier consume isDisplayingCode so it re-runs on toggle, and reset
the inline height on the collapse / no-measurable-editor paths so the block
returns to its header-only height.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Preview deployments

Host Test Results

    1 files  ±0      1 suites  ±0   1h 58m 34s ⏱️ - 2m 48s
4 597 tests +5  4 583 ✅ +5  14 💤 ±0  0 ❌ ±0 
4 612 runs  +1  4 598 ✅ +1  14 💤 ±0  0 ❌ ±0 

Results for commit 1410aca. ± Comparison against earlier commit 176c4ea.

Realm Server Test Results

    1 files  ±0      1 suites  ±0   19m 25s ⏱️ +32s
2 351 tests ±0  2 351 ✅ ±0  0 💤 ±0  0 ❌ ±0 
2 434 runs  ±0  2 434 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 1410aca. ± Comparison against earlier commit 176c4ea.

@FadhlanR
FadhlanR marked this pull request as ready for review August 28, 2026 12:22
@FadhlanR
FadhlanR requested review from a team and lukemelia August 28, 2026 12:22

@backspace backspace left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖]

I went after what changes on the paths this modifier previously never ran on — expand, remount, rebuild — and checked the height math against the code block's own CSS; I did not exercise it in a browser.

The collapse fix is correct and the remount reproduction in the test is real. But consuming isDisplayingCode also activates the height stamp on the expand path, where getContentHeight() over-measures anything past the editor's 250px cap — so for long tool calls this moves the empty block from "Hide Info" to "View Info". That is the one blocking item.

  1. Drop the outer height stamp, or measure the editor's rendered box instead of its content height — see the scrollBottomIntoView thread. Blocking.
  2. Confirm you want "View Info" to scroll the panel; that behavior falls out of the same change — same thread. Needs an answer, not a change.
  3. Add expanded-state coverage with a payload past the cap — see the tools-test thread. Non-blocking.

Percy is the only non-green check, with 2 unreviewed visual changes. Worth opening rather than bulk-approving, since this change can alter the code block's box height.

let editor = this.args.monacoSDK.editor
.getEditors()
.find((editor) => element.contains(editor.getContainerDomNode()));
let editorHeight = editor?.getContentHeight() ?? 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖]

Consuming isDisplayingCode also makes the expand path stamp a height for the first time, and this math over-measures — so as written the PR trades an empty block after "Hide Info" for one after "View Info".

getContentHeight() is Monaco's full content height, but .code-block-editor is capped at --code-block-max-height (250px) in ai-assistant/code-block/index.gts, and the outer .code-block section has no max-height of its own, only overflow: hidden. The stamp is therefore header + contentHeight while the box renders header + min(contentHeight, 250). Monaco's line height here is 1.5 × 12px on macOS (1.35 × elsewhere) plus 16px of padding, so past ~13 lines of tool-call JSON — routine for a patchCardInstance patch or a search filter — expanding leaves a contentHeight − 250 gap. The // max-height is constrained by CSS note on the stamp is what makes it read as safe; that cap is on the child, not on element.

It only bites now because expand previously never re-ran the modifier. And the editor really is measurable on that re-run: Glimmer runs scheduled modifier installs before scheduled updates within one commit, so the freshly created Monaco editor already reports a content height when this update lands.

The stamp is also redundant — the Monaco modifier sizes the editor div and CSS clamps it, so header + renderedEditorHeight is the section's natural height. Dropping it removes both the over-stamp and the need to clear anything:

private scrollBottomIntoView = modifier((element: HTMLElement) => {
  // Consume the toggle flag so this re-runs when the code area opens.
  if (!this.isDisplayingCode) {
    return;
  }
  this.scrollIntoView(element.parentElement as HTMLElement);
});

To keep the stamp instead, measure the rendered box: editor?.getContainerDomNode().offsetHeight in place of getContentHeight().

Either shape carries one decision: expand now reaches scrollIntoView, which it never did on a normal mount, so clicking "View Info" on a message up in the scrollback will scroll the panel. Likely the modifier's original intent, but it is new user-visible behavior — worth confirming you want it.

Regression introduced here, on top of a calculation that was previously only reachable through the remount path. Blocking.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖]

Agreed — real regression, and it's now fixed by dropping the outer height stamp entirely (1410aca). The Monaco modifier already sizes .code-block-editor and CSS caps it at 250px, so the section sizes to its content: no over-measure on expand, and nothing to clear on collapse.

Context that argues for removing it rather than patching the math — the stamp predates the self-sizing editor. It was added in Dec 2024 when the code rendered into a plain monaco-container with no height of its own, so back then the stamp was the only thing giving the code area a size. The self-sizing editor (onDidContentSizeChange) arrived with the CodeBlock refactor in #2859 (Jul 2025), which made the stamp redundant; it just survived the refactor still reading Monaco's uncapped content height. So this removes a leftover, not a safeguard.

On scroll-on-expand: confirmed intentional. "View Info" now brings the code into view, which matches the modifier's original purpose — keeping it.

Comment on lines +1304 to +1312
let codeBlock = find(
'[data-test-tool-call-id="hide-info-height"] .tool-code-block',
) as HTMLElement;
assert.ok(codeBlock, 'tool code block element exists');
assert.strictEqual(
codeBlock.style.height,
'',
'inline height is cleared so the block collapses to its header-only height',
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖]

This pins the collapsed state but not the expanded one, which is where the height math is now newly exercised. The payload here renders 13 lines, just under the 250px editor cap, so it cannot distinguish a correct stamp from an over-stamp.

Add a case whose tool-call payload exceeds --code-block-max-height and assert, while expanded, that the section's height is no greater than the header plus the editor's rendered height. Against the current diff that fails — see the scrollBottomIntoView thread.

Smaller, on these lines: find(...) as HTMLElement is dereferenced immediately after a soft assert.ok, so a null match both fails an assertion and throws; and .tool-code-block carries no CSS rule anywhere in the repo, making it an invisible test-only hook nothing protects. An assert.dom(...).exists() before the read covers the first, and a data-test- attribute alongside the class would make the hook explicit.

Non-blocking; the coverage half is what would have caught the expand-path issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖]

Done:

  • Added expanding a tall tool call does not leave an empty gap below the code — a 30-line (over-cap) payload asserting that, while expanded, the section height doesn't exceed the sum of its rendered children (and carries no inline height). That fails against the old stamp and locks in the content-sizing behavior.
  • The collapse assertion now does assert.dom(...).exists() before dereferencing, so a null match fails cleanly instead of throwing.
  • Replaced the class-only .tool-code-block hook with an explicit data-test-tool-code-block attribute on the CodeBlock.

…ight

Drop the inline pixel height the scrollBottomIntoView modifier stamped on the
code block. The Monaco modifier already sizes the editor and CSS caps it, so
the section sizes to its content naturally: the block collapses back to its
header when the editor is removed, and it no longer over-measures on expand.

The previous approach measured Monaco's uncapped content height, which exceeds
the editor's 250px cap for long payloads, so it would have left an empty gap
below the code when expanding a tall tool call. The modifier now only brings
the code into view when it opens.

Add coverage for a tall (over-cap) payload asserting the expanded block does
not exceed its rendered children, and give the block an explicit test hook.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@FadhlanR

Copy link
Copy Markdown
Contributor Author

[Claude Code 🤖]

CI is green — all 16 Host Test shards pass with the new coverage, plus Lint / Realm / Matrix / Boxel CLI. The only non-pass is the Percy visual gate (1 change needs review), expected since the code block's rendered height changes; opening it for review rather than bulk-approving, per your note.

@FadhlanR
FadhlanR requested a review from backspace August 31, 2026 10:04
@FadhlanR
FadhlanR merged commit 00b60db into main Sep 1, 2026
70 of 71 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants